
#ifndef __H_ROOM_M__
#define __H_ROOM_M__
#include "util.hpp"
#include "db.hpp"
#include "online.hpp"

typedef enum{GAME_START,GAME_OVER} room_status;

#define BOARD_ROW 15
#define BOARD_COL 15
#define WRITE_COLOR 1
#define BLACK_COLOR 2

class room
{
public:
    room(uint64_t room_id, user_table* ut, online_manager* om)
        :_room_id(room_id), _status(GAME_START), _play_count(0)
        , _ut(ut), _om(om), _board(BOARD_ROW, vector<int>(BOARD_COL, 0))
    {
        DLOG("房间初始化成功！");
    }
    ~room() { DLOG("房间销毁成功！"); }
    uint64_t get_room_id() { return _room_id; }
    room_status get_room_status() { return _status; }
    int get_play_count() { return _play_count; }
    void set_white_id(uint64_t uid) { _white_id = uid; _play_count++;}
    void set_black_id(uint64_t uid) { _black_id = uid; _play_count++;}
    uint64_t get_white_id() { return _white_id; }
    uint64_t get_black_id() { return _black_id; }


    // 处理下棋动作
    Json::Value handle_chess(Json::Value& req)
    {
        Json::Value json_resp = req;
        int chess_row = req["row"].asInt();
        int chess_col = req["col"].asInt();
        uint64_t cur_uid = req["uid"].asUInt64();
        // 判断玩家是否在线， 任意一方不在线对方胜利
        if(_om->is_in_game_room(_white_id) == false)
        {
            json_resp["result"] = true;
            json_resp["reason"] = "对方掉线，取得胜利！";
            json_resp["winner"] = (Json::UInt64)_black_id;
            return json_resp;
        }
        if(_om->is_in_game_room(_black_id) == false)
        {
            json_resp["result"] = true;
            json_resp["reason"] = "对方掉线，取得胜利！";
            json_resp["winner"] = (Json::UInt64)_white_id;
            return json_resp;
        }
        // 获取走棋位置，判断下棋位置是否有棋子，
        if(_board[chess_row][chess_col] != 0)
        {
            json_resp["result"] = false;
            json_resp["reason"] = "当前位置已经棋子";
            return json_resp;
        }
        int cur_color = cur_uid == _white_id ? WRITE_COLOR : BLACK_COLOR;
        _board[chess_row][chess_col] = cur_color;

        // 判断是否有胜利者
        uint64_t winner_id = check_win(chess_row, chess_col, cur_color);
        if( winner_id != 0)
        {
            json_resp["reason"] = "五子连线，游戏胜利！";
        }
        
        json_resp["result"] = true;
        json_resp["winner"] = (Json::UInt64)winner_id;

        return json_resp;
    }
    // 处理聊天动作
    Json::Value handle_chat(Json::Value& req)
    {
        Json::Value json_resp = req;
        // 检查消息是否为空
        string msg = req["message"].asString();
        if(msg.empty())
        {
            json_resp["result"] = false;
            json_resp["reason"] = "消息为空";
            return json_resp;
        }

        // 检查有没有敏感词汇
        auto it = msg.find("傻逼");
        if(it != string::npos)
        {
            json_resp["result"] = false;
            json_resp["reason"] = "消息中包含敏感词汇";
            return json_resp;
        }

        json_resp["result"] = true;
        return json_resp;
    }
    // 处理玩家退出房间动作
    void handle_exit(uint64_t uid)
    {
        Json::Value json_resp;
        // 判断退出时的游戏状态，如果游戏进行中退出则对方胜利
        if(_status == GAME_START)
        {
            uint64_t win_id = uid == _white_id ? _black_id : _white_id;
            uint64_t lose_id = win_id == _white_id ? _black_id : _white_id;
            json_resp["optype"] = "put_chess";
            json_resp["result"] = true;
            json_resp["reason"] = "对方玩家退出房间，游戏胜利！";
            json_resp["room_id"] = (Json::UInt64)_room_id;
            json_resp["uid"] = (Json::UInt64)uid;
            json_resp["row"] = -1;
            json_resp["col"] = -1;
            json_resp["winner"] = (Json::UInt64)win_id;

            // 数据库的数据也要修改
            _ut->win(win_id);
            _ut->lose(lose_id);
            // 房间状态改为游戏结束
            _status = GAME_OVER;

            boardcast(json_resp);
        }
        // 游戏结束状态则游戏玩家减少
        _play_count--;
    }
    // 总的处理函数
    void handler_message(Json::Value& req)
    {
        Json::Value json_resp;
        // 1.检验房间号是否一致
        uint64_t rid = req["room_id"].asUInt64();
        if( rid != _room_id)
        {
            json_resp["optype"] = req["optype"].asString();
            json_resp["result"] = false;
            json_resp["reason"] = "房间号不一致！";

            return boardcast(json_resp);
        }

        // 2. 根据不同请求，处理不同动作
        if(req["optype"].asString() == "put_chess")
        {
            json_resp = handle_chess(req);
            uint64_t win_id =  json_resp["winner"].asUInt64();
            if(win_id != 0)
            {
                uint64_t lose_id = win_id == _white_id ? _black_id : _white_id;
                _ut->win(win_id);
                _ut->lose(lose_id);
                _status = GAME_OVER;
            }
        }
        else if(req["optype"].asString() == "chat")
        {
            json_resp = handle_chat(req);
        }
        else
        {
            json_resp["optype"] = req["optype"].asString();
            json_resp["result"] = false;
            json_resp["reason"] = "未知请求类型";
        }
        boardcast(json_resp);
    }
    // 广播消息
    void boardcast(Json::Value& req)
    {
        // 
        string body;
        if(json_util::serialize(req, body) == false)
            { return ;}
        
        // 通过id在在线用户管理模块中获取通信连接
        // 发送响应消息
        wsserver_t::connection_ptr wconn = _om->get_conn_form_room(_white_id);
        if(wconn.get() != nullptr)
        {
            wconn->send(body);
        }
        wsserver_t::connection_ptr bconn = _om->get_conn_form_room(_black_id);
        if(bconn.get() != nullptr)
        {
            bconn->send(body);
        }

        return;
    }
private:
    // 判断是否有五子连线
    bool five(int row, int col, int row_off, int col_off, int color)
    {
        int count = 1;
        int search_row = row + row_off;
        int search_col = col + col_off;
        while(search_row >= 0 && search_row < BOARD_ROW 
            && search_col >= 0 && search_col < BOARD_COL 
            && _board[search_row][search_col] == color)
            {
                count++;
                search_row += row_off;
                search_col += col_off;
            }
        search_row = row - row_off;
        search_col = col - col_off;
        while(search_row >= 0 && search_row < BOARD_ROW 
            && search_col >= 0 && search_col < BOARD_COL 
            && _board[search_row][search_col] == color)
            {
                count++;
                search_row -= row_off;
                search_col -= col_off;
            }

        return count >= 5;
    }
    // 判断是否有胜利者
    uint64_t check_win(int row, int col, int color)
    {
        // 判断横向，纵向，两条对角线是否有五子连线
        if(five(row, col, 0, 1, color) || five(row, col, 1, 0, color)
         || five(row, col, 1, 1, color)|| five(row, col, 1, -1, color))
        {
            return color == WRITE_COLOR ? _white_id : _black_id;
        }
        return 0;
    }
private:
    uint64_t _room_id;
    room_status _status;
    int _play_count;
    uint64_t _white_id;
    uint64_t _black_id;
    user_table* _ut;
    online_manager* _om;
    vector<vector<int>> _board;
};

using room_ptr = shared_ptr<room>;
class room_manager
{
public:
    room_manager(user_table* ut, online_manager* om)
        :_next_id(1), _ut(ut), _om(om)
    { DLOG("房间管理模块初识化完成！"); }
    ~room_manager() { DLOG("房间管理模块销毁完成！"); }
    room_ptr create_room(uint64_t uid1, uint64_t uid2)
    {
        // 1. 判断用户是否在游戏大厅
        if(_om->is_in_game_hall(uid1) == false)
        {
            ELOG("%d 用户当前不在线，房间创建失败", uid1);
            return room_ptr();
        }
        if(_om->is_in_game_hall(uid2) ==false)
        {
            ELOG("%d 用户当前不在线，房间创建失败", uid2);
            return room_ptr();
        }
        // 2. 创建房间，将用户信息加入到房间中
        unique_lock<mutex> lock(_mutex);
        room_ptr rp(new room(_next_id, _ut, _om));
        rp->set_white_id(uid1);
        rp->set_black_id(uid2);

        // 3. 将房间管理起来
        _rooms.insert(make_pair(_next_id, rp));
        _users.insert(make_pair(uid1, _next_id));
        _users.insert(make_pair(uid2, _next_id));
        _next_id +=1 ; //房间号自增
        // 4. 返回房间的信息
        return rp;
    }
    // 通过房间ID获取房间信息
    room_ptr get_room_by_rid(uint64_t rid)
    {
        
        unique_lock<mutex> lock(_mutex);
        auto it = _rooms.find(rid);
        if(it == _rooms.end())
        {

            return room_ptr();
        }
        return it->second;
    }
    // 通过用户ID获取房间信息
    room_ptr get_room_by_uid(uint64_t uid)
    {
        uint64_t rid = 0;
        {
            unique_lock<mutex> lock(_mutex);
            auto it = _users.find(uid);
            if(it == _users.end())
            {
                return room_ptr();
            }
            rid = it->second;
        }
       return get_room_by_rid(rid);
    }
    // 销毁房间
    void remove_room(uint64_t rid)
    {
        // 1.通过房间id获取房间信息
        room_ptr rp = get_room_by_rid(rid);
        if(rp.get() == nullptr)
            { return ;}

        // 2. 通过房间信息获取房间中的所有用户ID
        uint64_t uid1 = rp->get_white_id();
        uint64_t uid2 = rp->get_black_id();
        // 3. 移除房间中管理的用户信息
        unique_lock<mutex> lock(_mutex);
        _users.erase(uid1);
        _users.erase(uid2);
        // 4. 移除房间信息
        _rooms.erase(rid);

    }
    // 删除房间中的指定用户，房间中没有用户则销毁房间
    void remove_room_user(uint64_t uid)
    {
        room_ptr rp = get_room_by_uid(uid);
        if(rp.get() == nullptr)
            {return ;}
        rp->handle_exit(uid);
        if(rp->get_play_count() == 0)
        {
            remove_room(rp->get_room_id());
        }
    }

private:
    uint64_t _next_id;
    mutex _mutex;
    user_table* _ut;
    online_manager* _om;
    unordered_map<uint64_t, room_ptr> _rooms;
    unordered_map<uint64_t, uint64_t> _users;
};

#endif